package at.ac.tuwien.dse.health.event.listener;

import at.ac.tuwien.dse.health.event.bus.EventBus;
import at.ac.tuwien.dse.health.event.bus.EventTarget;
import at.ac.tuwien.dse.health.event.type.Event;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.remoting.rmi.RmiProxyFactoryBean;
import org.springframework.remoting.rmi.RmiServiceExporter;

import java.io.Serializable;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

/**
 * Uses RMI to send and receive {@link Event Events}.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 * @see RmiServiceExporter
 * @see RmiProxyFactoryBean
 */
public class RmiEventListener implements EventListener, InitializingBean, DisposableBean {
	EventBus eventBus;
	RmiServiceExporter serviceExporter;
	RmiProxyFactoryBean proxyFactoryBean;
	String serviceName;

	@Override
	public void handleEvent(EventTarget eventTarget, Event<? extends Serializable> event) {
		if (serviceExporter != null) {
			eventBus.delegate(event);
		} else if (proxyFactoryBean != null) {
			EventListener service = (EventListener) proxyFactoryBean.getObject();
			service.handleEvent(null, event);
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		if (checkNotNull(serviceName, "'serviceName' must not be null").startsWith("rmi://")) {
			proxyFactoryBean = proxyFactoryBean != null ? proxyFactoryBean : new RmiProxyFactoryBean();
			proxyFactoryBean.setServiceUrl(serviceName);
			proxyFactoryBean.setServiceInterface(EventListener.class);
			proxyFactoryBean.afterPropertiesSet();
		} else {
			checkState(eventBus != null, "'eventBus' must provided along with the 'serviceExporter'");
			serviceExporter = serviceExporter != null ? serviceExporter : new RmiServiceExporter();
			serviceExporter.setServiceName(serviceName);
			serviceExporter.setServiceInterface(EventListener.class);
			serviceExporter.setService(this);
			serviceExporter.afterPropertiesSet();
		}

		checkState(proxyFactoryBean == null || serviceExporter == null,
				getClass().getSimpleName() + " can either be used in sender or receiver mode.");
	}

	@Override
	public void destroy() throws Exception {
		if (serviceExporter != null) {
			serviceExporter.destroy();
		}
	}

	public void setServiceExporter(RmiServiceExporter serviceExporter) {
		this.serviceExporter = serviceExporter;
	}

	public void setProxyFactoryBean(RmiProxyFactoryBean proxyFactoryBean) {
		this.proxyFactoryBean = proxyFactoryBean;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}

	public void setServiceName(String serviceName) {
		this.serviceName = serviceName;
	}
}
